#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
每个过滤器5条边界测试。
输出接口：run_tests() -> List[dict]
case: {"name": str, "passed": bool, "details": str}
"""

from typing import List, Dict

from filters.filter_registry import FilterRegistry


def _case(name: str, passed: bool, details: str = "") -> Dict:
    return {"name": name, "passed": bool(passed), "details": details}


def _safe_should_filter(rule, add_content: str, remove_content: str, hunk_changes: List[Dict]):
    try:
        return True, rule.should_filter(add_content, remove_content, hunk_changes)
    except Exception as e:
        return False, f"exception: {e}"


def _file_change(path: str, add: str = "", remove: str = "") -> List[Dict]:
    return [{"type": "context", "content": ""}, {"type": "add", "content": add}, {"type": "remove", "content": remove}, {"type": "context", "content": ""}, {"file_path": path}]


def _hunk(add: str = "", remove: str = "") -> List[Dict]:
    return [{"type": "context", "content": ""}, {"type": "add", "content": add}, {"type": "remove", "content": remove}, {"type": "context", "content": ""}]


def _test_filter(name: str) -> List[Dict]:
     cases: List[Dict] = []
     cls = FilterRegistry.get(name)
     rule = cls()

     def record(case_name: str, add: str, remove: str, hunk: List[Dict], expect: bool):
         ok, res = _safe_should_filter(rule, add, remove, hunk)
         passed = ok and (res is expect)
         detail = "ok" if ok else str(res)
         cases.append(_case(f"{name}:{case_name}", passed, details=detail if passed else f"got={res} expect={expect}"))

     if name == 'type_base':
         record('modify_allowed', 'x', 'y', _hunk(add='x', remove='y'), False)
         record('add_filtered', 'hello', '', _hunk(add='hello'), True)
         record('delete_filtered', '', 'world', _hunk(remove='world'), True)
         record('unknown_filtered', '', '', _hunk(), True)
         record('long_modify_allowed', 'abcde', 'vwxyz', _hunk(add='abcde', remove='vwxyz'), False)

     elif name == 'trivial_whitespace':
         record('spaces_only', 'a b c', 'abc', _hunk(add='a b c', remove='abc'), True)
         record('leading_trailing_blanks', '\n\nline\n', 'line', _hunk(add='\n\nline\n', remove='line'), True)
         record('tabs_vs_spaces', 'a\tb', 'a  b', _hunk(add='a\tb', remove='a  b'), True)
         record('content_diff', 'ab', 'ac', _hunk(add='ab', remove='ac'), False)
         record('line_count_diff_but_equal_ignoring_ws', 'a \n b', 'a\nb', _hunk(add='a \n b', remove='a\nb'), True)

     elif name == 'code_block_language_tag':
         record('lang_change', '```python', '```', _hunk(add='```python', remove='```'), True)
         record('switch_lang', '```ts', '```js', _hunk(add='```ts', remove='```js'), True)
         record('not_code_fence', '```python', 'def x()', _hunk(add='```python', remove='def x()'), False)
         record('same_tag', '```py', '```py', _hunk(add='```py', remove='```py'), False)
         record('invalid_marker', '``py', '```py', _hunk(add='``py', remove='```py'), False)

     elif name == 'url_change':
         record('query_order', 'https://a.com/x?p=1&q=2', 'https://a.com/x?q=2&p=1', _hunk(add='https://a.com/x?p=1&q=2', remove='https://a.com/x?q=2&p=1'), True)
         record('host_diff', 'https://a.com/x', 'https://b.com/x', _hunk(add='https://a.com/x', remove='https://b.com/x'), False)
         record('path_diff', 'https://a.com/x/y', 'https://a.com/x', _hunk(add='https://a.com/x/y', remove='https://a.com/x'), False)
         record('query_value_diff', 'https://a.com/x?p=1', 'https://a.com/x?p=2', _hunk(add='https://a.com/x?p=1', remove='https://a.com/x?p=2'), False)
         record('non_http', 'ftp://a.com/x', 'ftp://a.com/x', _hunk(add='ftp://a.com/x', remove='ftp://a.com/x'), False)

     elif name == 'file_extension':
         record('md_allowed', 'x', 'y', [{'file_path': 'README.md'}], False)
         record('py_filtered', 'x', 'y', [{'file_path': 'main.py'}], True)
         record('mixed_any_allowed', 'x', 'y', [{'file_path': 'a.py'}, {'file_path': 'b.MD'}], False)
         record('no_file_info', 'x', 'y', [], False)
         record('uppercase_md_allowed', 'x', 'y', [{'file_path': 'DOC.MD'}], False)

     elif name == 'markdown_heading_level':
         record('level_change', '## Title', '# Title', _hunk(add='## Title', remove='# Title'), True)
         record('same_text_diff_level_no_space', '###Title', '# Title', _hunk(add='###Title', remove='# Title'), True)
         record('same_level', '# Title', '# Title', _hunk(add='# Title', remove='# Title'), False)
         record('text_diff', '## Title1', '# Title2', _hunk(add='## Title1', remove='# Title2'), False)
         record('non_heading', 'Title', 'Title', _hunk(add='Title', remove='Title'), False)

     elif name == 'punctuation_change':
         record('end_punct_added', 'Hello.', 'Hello', _hunk(add='Hello.', remove='Hello'), True)
         record('cn_en_replacement', '，', ',', _hunk(add='，', remove=','), True)
         record('multi_non_punct_diff', 'ab', 'ac', _hunk(add='ab', remove='ac'), False)
         record('single_pair', '。', '.', _hunk(add='。', remove='.'), True)
         record('pathological_many_changes', 'a，b。', 'a,b!', _hunk(add='a，b。', remove='a,b!'), False)

     elif name == 'list_style_change':
         record('unordered_symbol_change', '- item', '* item', _hunk(add='- item', remove='* item'), True)
         record('ordered_symbol_change', '1) item', '1. item', _hunk(add='1) item', remove='1. item'), True)
         record('ordered_number_change', '2. item', '1. item', _hunk(add='2. item', remove='1. item'), False)
         record('text_change', '- item1', '- item2', _hunk(add='- item1', remove='- item2'), False)
         record('non_list', 'paragraph', 'paragraph', _hunk(add='paragraph', remove='paragraph'), False)

     elif name == 'content_length':
         record('add_short', 'abc', '', _hunk(add='abc'), True)
         record('delete_short', '', 'abcd', _hunk(remove='abcd'), True)
         record('modify_total_short', 'a', 'b', _hunk(add='a', remove='b'), True)
         record('both_empty', '', '', _hunk(), True)
         record('enough_length', 'hello', '', _hunk(add='hello'), False)

     elif name == 'trailing_symbol_change':
         record('different_trailing', 'Hello...', 'Hello!!', _hunk(add='Hello...', remove='Hello!!'), True)
         record('no_trailing_diff', 'Hello', 'Hello', _hunk(add='Hello', remove='Hello'), False)
         record('whitespace_trailing', 'Hello  ', 'Hello\t', _hunk(add='Hello  ', remove='Hello\t'), True)
         record('core_diff', 'Hello', 'World', _hunk(add='Hello', remove='World'), False)
         record('empty_vs_space', ' ', '', _hunk(add=' ', remove=''), False)

    

     else:
         # Fallback: basic smoke tests if new filters are registered in future
         record('empty', '', '', _hunk(), False)
         record('add_only', 'a', '', _hunk(add='a'), False)
         record('remove_only', '', 'b', _hunk(remove='b'), False)
         record('modify', 'x', 'y', _hunk(add='x', remove='y'), False)
         record('file_ctx', 'x', 'y', [{'file_path': 'README.md'}], False)

     return cases


def run_tests() -> List[Dict]:
    results: List[Dict] = []
    for name in FilterRegistry.list_available():
        results.extend(_test_filter(name))
    return results


